//
//  UIButton+Extend.swift
//  GLSwiftProject
//
//  Created by HeHeAdmin on 2019/5/16.
//  Copyright © 2019 HeHeAdmin. All rights reserved.
//

import UIKit

//MARK: ---- 初始化 ----
extension UIButton {
    
   public convenience init(x:CGFloat,y:CGFloat,w:CGFloat,h:CGFloat,style:UIButton.ButtonType) {
        
        self.init(type: style)
        frame = CGRect(x: x, y: y, width: w, height: h)
    }
}

//MARK: ---- 常见set方法 ----
extension UIButton {
    
    /// 设置选中和非选中文字颜色
    ///
    /// - Parameters:
    ///   - normalColor: normalColor
    ///   - selectedColor: selectedColor
   public func set_GLTitleColor(normalColor:UIColor,selectedColor:UIColor) {
        setTitleColor(normalColor, for: .normal)
        setTitleColor(selectedColor, for: .selected)
    }
    
    /// 设置选中和非选中图片
    ///
    /// - Parameters:
    ///   - normalImage: normalImage
    ///   - selecedImage: selecedImage
   public func set_GLImage(normalImage:UIImage,selecedImage:UIImage) {
        
        setImage(normalImage, for: .normal)
        setImage(selecedImage, for: .selected)
    }
    
    /// 设置非选中状态的title和color
    ///
    /// - Parameters:
    ///   - title: title
    ///   - titleColor: titleColor
   public func set_GLTitleWithTitleColor(title:String,titleColor:UIColor) {
        
        setTitle(title, for: .normal)
        setTitleColor(titleColor, for: .normal)
    }
    
    /// 设置未选中状态下的title和image
    ///
    /// - Parameters:
    ///   - title: title
    ///   - image: image
   public func set_GLTitleWithImage(title:String,image:UIImage) {
        
        setImage(image, for: .normal)
        setTitle(title, for: .normal)
    }
}


//MARK: ---- runtime添加属性 ----
struct RunTimeButtonKey {
    
    ///连续两次的点击相差的时间
    static let timeInterval = UnsafeRawPointer.init(bitPattern: "timeInterval".hashValue)
    
    ///点击区域
    static let topNameKey = UnsafeRawPointer.init(bitPattern: "topNameKey".hashValue)
    static let rightNameKey = UnsafeRawPointer.init(bitPattern: "rightNameKey".hashValue)
    static let bottomNameKey = UnsafeRawPointer.init(bitPattern: "bottomNameKey".hashValue)
    static let leftNameKey = UnsafeRawPointer.init(bitPattern: "leftNameKey".hashValue)
    
}

extension UIButton {
    
    //添加属性，设置timeInterval时，修改button的执行事件
    var timeInterval:CGFloat? {
        set {
            objc_setAssociatedObject(self, RunTimeButtonKey.timeInterval!, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
            UIButton.changeFunction
        }
        get {
            return objc_getAssociatedObject(self, RunTimeButtonKey.timeInterval!) as? CGFloat
        }
    }
    
    private static let changeFunction: () = {
        //交换方法
        let systemMethod = class_getInstanceMethod(UIButton.classForCoder(), #selector(UIButton.sendAction(_:to:for:)))
        let swizzMethod = class_getInstanceMethod(UIButton.classForCoder(), #selector(UIButton.mySendAction(_:to:for:)))
        method_exchangeImplementations(systemMethod!, swizzMethod!)
    }()
    
    @objc private dynamic func mySendAction(_ action:Selector,to target:Any?,for event:UIEvent?){
        
        isUserInteractionEnabled = false
        let time:TimeInterval = TimeInterval(timeInterval ?? 0.0)
        DispatchQueue.main.asyncAfter(deadline: .now() + time) {
            self.isUserInteractionEnabled = true
        }
        mySendAction(action, to: target, for: event)
    }
    
    //扩大点击响应事件
    var topEdge:CGFloat? {
        
        set {
            objc_setAssociatedObject(self, RunTimeButtonKey.topNameKey!, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
        }
        get {
            return objc_getAssociatedObject(self, RunTimeButtonKey.topNameKey!) as? CGFloat
        }
    }
    
    var leftEdge:CGFloat? {
        set {
            objc_setAssociatedObject(self, RunTimeButtonKey.leftNameKey!, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
        }
        get {
            return objc_getAssociatedObject(self, RunTimeButtonKey.leftNameKey!) as? CGFloat
        }
    }
    
    var rightEdge:CGFloat? {
        set {
            objc_setAssociatedObject(self, RunTimeButtonKey.rightNameKey!, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
        }
        get {
            return objc_getAssociatedObject(self, RunTimeButtonKey.rightNameKey!) as? CGFloat
        }
    }
    
    var bottomEdge:CGFloat? {
        set {
            objc_setAssociatedObject(self, RunTimeButtonKey.bottomNameKey!, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
        }
        get {
            return objc_getAssociatedObject(self, RunTimeButtonKey.bottomNameKey!) as? CGFloat
        }
    }
    
    /// 扩大点击区域
    ///
    /// - Parameters:
    ///   - top: 上
    ///   - right: 右
    ///   - bottom: 下
    ///   - left: 左
   public func gxl_setEnlargeEdge(top:CGFloat,right:CGFloat,bottom:CGFloat,left:CGFloat) {
        
        self.topEdge = top
        self.rightEdge = right
        self.bottomEdge = bottom
        self.leftEdge = left
    }
    
    open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        let left = self.leftEdge ?? 0
        let right = self.rightEdge ?? 0
        let bottom = self.bottomEdge ?? 0
        let top = self.topEdge ?? 0
        
        var rect:CGRect
        if (left > 0 || right > 0 || bottom > 0 || top > 0) {
            rect = CGRect(x: self.bounds.origin.x - left, y: self.bounds.origin.y - top, width:self.bounds.size.width + left + right, height: self.bounds.size.height + top + bottom)
        }else {
            rect = self.bounds
        }
        
        if (rect.contains(self.bounds)) {
            return super.hitTest(point, with: event)
        }
        
        return rect.contains(point) ? self : nil
    }
}
//MARK: 渐变色
extension UIButton {
    
    /// 背景色 -- 渐变色
    ///
    /// - Parameters:
    ///   - colors: 颜色
    ///   - direction: 方向
    ///   - state: 状态
    public func setGradientBackgroundColors(_ colors: [UIColor], direction: DTImageGradientDirection, for state: UIControl.State) {
        if colors.count > 1 {
            // Gradient background
            setBackgroundImage(UIImage(size: CGSize(width: 1, height: 1), direction: direction, colors: colors), for: state)
        }
        else {
            if let color = colors.first {
                // Mono color background
                setBackgroundImage(UIImage(color: color, size: CGSize(width: 1, height: 1)), for: state)
            }
            else {
                // Default background color
                setBackgroundImage(nil, for: state)
            }
        }
    }
}


extension UIButton {
    
    /// 图片和文字的位置
    ///
    /// - Parameters:
    ///   - anImage: 图片名称
    ///   - title: 文字
    ///   - titlePosition: 文字相对于图片的位置
    ///   - additionalSpacing: 间隙
    ///   - state: 状态
    public func set(image anImage: UIImage?, title: String,
                   titlePosition: UIView.ContentMode, additionalSpacing: CGFloat, state: UIControl.State){
        self.imageView?.contentMode = .center
        self.setImage(anImage, for: state)
        
        positionLabelRespectToImage(title: title, position: titlePosition, spacing: additionalSpacing)
        
        self.titleLabel?.contentMode = .center
        self.setTitle(title, for: state)
    }
    
    private func positionLabelRespectToImage(title: String, position: UIView.ContentMode,
                                             spacing: CGFloat) {
        let imageSize = self.imageRect(forContentRect: self.frame)
        let titleFont = self.titleLabel?.font!
        let titleSize = title.size(withAttributes: [NSAttributedString.Key.font: titleFont!])
        
        var titleInsets: UIEdgeInsets
        var imageInsets: UIEdgeInsets
        
        switch (position){
        case .top:
            titleInsets = UIEdgeInsets(top: -(imageSize.height + titleSize.height + spacing),
                                       left: -(imageSize.width), bottom: 0, right: 0)
            imageInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: -titleSize.width)
        case .bottom:
            titleInsets = UIEdgeInsets(top: (imageSize.height + titleSize.height + spacing),
                                       left: -(imageSize.width), bottom: 0, right: 0)
            imageInsets = UIEdgeInsets(top: -15, left: 0, bottom: 0, right: -titleSize.width) //-15图片距顶距离
        case .left:
            titleInsets = UIEdgeInsets(top: 0, left: -(imageSize.width * 2), bottom: 0, right: 0)
            imageInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0,
                                       right: -(titleSize.width * 2 + spacing))
        case .right:
            titleInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: -spacing)
            imageInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        default:
            titleInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
            imageInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        }
        
        self.titleEdgeInsets = titleInsets
        self.imageEdgeInsets = imageInsets
    }
}

///MARK: 防止按钮重复点击
let defaultDuration = 3.0

extension UIButton{
    @objc func my_sendAction(action: Selector, to target: AnyObject?, forEvent event: UIEvent?) {
        
        if (self.isKind(of: UIButton.self)) {
            
            switch self.repeatButtonClickType {
            case .durationTime:
                clickDurationTime = clickDurationTime == 0 ? defaultDuration : clickDurationTime
                
                
                if isIgnoreEvent {
                    return
                } else if clickDurationTime > 0 {
                    isIgnoreEvent = true
                    // 在过了我们设置的duration之后，再将isIgnoreEvent置为false
                    DispatchQueue.global(qos: .default).asyncAfter(deadline: DispatchTime.now() + clickDurationTime) {
                        
                        
                        self.isIgnoreEvent = false
                    }
                    
                    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + clickDurationTime) {
                        self.isIgnoreEvent = false
                    }
                    
                    
                    my_sendAction(action: action, to: target, forEvent: event)
                }
                
                
            case .enentDone:
                
                if !isFinishEvent {
                    my_sendAction(action: action, to: target, forEvent: event)
                    isFinishEvent = true
                }
            }
            
        } else {
            my_sendAction(action: action, to: target, forEvent: event)
        }
    }
}

enum RepeatButtonClickType : Int{
    case durationTime = 0
    case enentDone
}


extension UIButton {
    
    private struct AssociatedKeys {
        static var clickDurationTime = "my_clickDurationTime"
        static var isIgnoreEvent = "my_isIgnoreEvent"
        static var isFinish = "my_isFinish"
        static var repeatButtonClickType = "repeatButtonClickType"
    }
    
    var repeatButtonClickType : RepeatButtonClickType {
        set {
            objc_setAssociatedObject(self, &AssociatedKeys.repeatButtonClickType, newValue as RepeatButtonClickType, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        
        get {
            
            if let clickDurationTime = objc_getAssociatedObject(self, &AssociatedKeys.repeatButtonClickType) as? RepeatButtonClickType {
                return clickDurationTime
            }
            
            return .durationTime
        }
    }
    
    // 点击间隔时间
    var clickDurationTime : TimeInterval {
        set {
            objc_setAssociatedObject(self, &AssociatedKeys.clickDurationTime, newValue as TimeInterval, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        
        get {
            
            if let clickDurationTime = objc_getAssociatedObject(self, &AssociatedKeys.clickDurationTime) as? TimeInterval {
                return clickDurationTime
            }
            
            return defaultDuration
        }
    }
    
    // 是否忽视点击事件
    var isIgnoreEvent : Bool {
        
        set {
            objc_setAssociatedObject(self, &AssociatedKeys.isIgnoreEvent, newValue as Bool, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        
        get {
            
            if let isIgnoreEvent = objc_getAssociatedObject(self, &AssociatedKeys.isIgnoreEvent) as? Bool {
                return isIgnoreEvent
            }
            
            return false
        }
    }
    
    
    // 是否完成点击事件
    var isFinishEvent : Bool {
        
        set {
            objc_setAssociatedObject(self, &AssociatedKeys.isFinish, newValue as Bool, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        
        get {
            
            if let isFinishEvent = objc_getAssociatedObject(self, &AssociatedKeys.isFinish) as? Bool {
                return isFinishEvent
            }
            
            return false
        }
    }
    
    public class func initializeOnceMethod() {
        
        
        if self !== UIButton.self {
            return
        }
        
        DispatchQueue.once(token: "jcgf.swift-Carsh-test-Crash"){
            
            let originalSelector = #selector(UIButton.sendAction)
            let swizzledSelector = #selector(UIButton.my_sendAction(action:to:forEvent:))
            
            let originalMethod = class_getInstanceMethod(self, originalSelector)
            let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)
            
            // 运行时为类添加我们自己写的my_sendAction(_:to:forEvent:)
            let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod!), method_getTypeEncoding(swizzledMethod!))
            
            if didAddMethod {
                // 如果添加成功，则交换方法
                class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod!), method_getTypeEncoding(originalMethod!))
            } else {
                // 如果添加失败，则交换方法的具体实现
                method_exchangeImplementations(originalMethod!, swizzledMethod!)
            }
        }
        
        
        
    }
    
}

extension DispatchQueue {
    
    private static var _onceTracker = "Stringss"
    
    public class func once(token: String, block: () -> ()) {
        
        objc_sync_enter(self)
        
        defer {
            
            objc_sync_exit(self)
            
        }
        
        if _onceTracker.contains(token) {
            
            return
            
        }
        
        _onceTracker.append(token)
        
        block()
        
    }
    
    func async(block: @escaping ()->()) {
        
        self.async(execute: block)
        
    }
    
    func after(time: DispatchTime, block: @escaping ()->()) {
        
        self.asyncAfter(deadline: time, execute: block)
        
    }
}
/*********倒计时 buttontype = custom**************/
// MARK: - 倒计时
extension UIButton{
    
    /// 倒计时
    ///
    /// - Parameters:
    ///   - count: 倒计时总时间
    ///   - title: 显示的title
    ///   - sTitle: 倒计时时显示的文字
    public func countDown(count: Int,title:String,sTitle:String){
        // 倒计时开始,禁止点击事件
        isEnabled = false
        
        // 保存当前的背景颜色
        let defaultColor = self.backgroundColor
        // 设置倒计时,按钮背景颜色
        backgroundColor = UIColor.gray
        
        var remainingCount: Int = count {
            willSet {
                setTitle("\(sTitle)(\(newValue))", for: .normal)
                
                if newValue <= 0 {
                    setTitle(title, for: .normal)
                }
            }
        }
        
        // 在global线程里创建一个时间源
        let codeTimer = DispatchSource.makeTimerSource(queue:DispatchQueue.global())
        // 设定这个时间源是每秒循环一次，立即开始
        codeTimer.schedule(deadline: .now(), repeating: .seconds(1))
        // 设定时间源的触发事件
        codeTimer.setEventHandler(handler: {
            
            // 返回主线程处理一些事件，更新UI等等
            DispatchQueue.main.async {
                // 每秒计时一次
                remainingCount -= 1
                // 时间到了取消时间源
                if remainingCount <= 0 {
                    self.backgroundColor = defaultColor
                    self.isEnabled = true
                    codeTimer.cancel()
                }
            }
        })
        // 启动时间源
        codeTimer.resume()
    }
}

///添加 登录的判断
//如何使用
/*：
1、在Applegate 中添加
UIButton.awake()
2、接收通知、移除通知
NotificationCenter.default.addObserver(self, selector: #selector(obser), name: NSNotification.Name.init("showLoginVC"), object: nil);
@objc func obser(){
    self.present(ViewController.init(), animated: true, completion: nil);
}

deinit {
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.init("showLoginVC"), object: nil);
}
 */


protocol SelfAware: class {
    static func awake()
    static func swizzlingForClass(_ forClass: AnyClass, originalSelector: Selector, swizzledSelector: Selector)
}

extension SelfAware {
    static func swizzlingForClass(_ forClass: AnyClass, originalSelector: Selector, swizzledSelector: Selector) {
        let originalMethod = class_getInstanceMethod(forClass, originalSelector)
        let swizzledMethod = class_getInstanceMethod(forClass, swizzledSelector)
        guard (originalMethod != nil && swizzledMethod != nil) else {
            return
        }
        if class_addMethod(forClass, originalSelector, method_getImplementation(swizzledMethod!), method_getTypeEncoding(swizzledMethod!)) {
            class_replaceMethod(forClass, swizzledSelector, method_getImplementation(originalMethod!), method_getTypeEncoding(originalMethod!))
        } else {
            method_exchangeImplementations(originalMethod!, swizzledMethod!)
        }
    }
}

extension UIButton: SelfAware {
    private struct AssociatedKey{
        /// 是否需要判断  用户登录,默认 不判断（false）
        static var judgeLogin:Bool = false;
    }
    var judgeLogin:Bool {
        get{
            if let bol = objc_getAssociatedObject(self, &AssociatedKey.judgeLogin) as? Bool {
                return bol
            }
            return false
        }
        set{
            objc_setAssociatedObject(self, &AssociatedKey.judgeLogin, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_COPY_NONATOMIC)
        }

    }
        
    
    static func awake() {
        UIButton.takeOnceTime
    }
    private static let takeOnceTime: Void = {
        let originalSelector = #selector(sendAction)
        let swizzledSelector = #selector(xxx_sendAction(action:to:forEvent:))
        swizzlingForClass(UIButton.self, originalSelector: originalSelector, swizzledSelector: swizzledSelector)
    }()
    
    @objc public func xxx_sendAction(action: Selector, to: AnyObject!, forEvent: UIEvent!) {
        if self.judgeLogin {
            if let isLogin = UserDefaults.standard.value(forKey: "isLogin") as? Bool {
                if isLogin {
                    xxx_sendAction(action: action, to: to, forEvent: forEvent)
                }else{
                    NotificationCenter.default.post(name: NSNotification.Name.init("showLoginVC"), object: nil);
                }
            }else{
                NotificationCenter.default.post(name: NSNotification.Name.init("showLoginVC"), object: nil);
            }
        }else{
            xxx_sendAction(action: action, to: to, forEvent: forEvent)
        }
    }
}
///
